package com.file.system.plugin.file;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.file.system.entity.dict.SystemPath;
import com.file.system.entity.res.CommonResult;
import com.file.system.entity.system.WebFile;
import com.file.system.entity.system.WebFileSystem;
import com.file.system.plugin.shiro.ShiroTools;
import com.file.system.service.impl.system.WebFileServiceImpl;
import com.file.system.service.impl.system.WebFileSystemServiceImpl;
import com.file.system.service.system.IWebFileService;
import com.file.system.service.system.IWebFileSystemService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;

import static cn.hutool.core.util.IdUtil.randomUUID;
import static com.file.system.tools.Formater.*;


/**
 * 文件上传工具
 */
@Configuration
@Component
public class FileTool {

    @Autowired
    private IWebFileSystemService iwebFileSystemService;
    @Autowired
    private IWebFileService iwebFileService;
    //根路径
    public static String rootPath;
    //分布式文件夹信息id
    public static final Long sysFileId = 10000L;

    public FileTool() {

        init();
    }

    /**
     * 初始化路径
     */
    public void init() {
        if (ObjectUtil.isNull(iwebFileSystemService)) {
            iwebFileSystemService = SpringUtil.getBean(WebFileSystemServiceImpl.class);
        }
        if (ObjectUtil.isNull(iwebFileService)) {
            iwebFileService = SpringUtil.getBean(WebFileServiceImpl.class);
        }
        // 获取文件系统
        WebFileSystem fileSystem = iwebFileSystemService.getById(sysFileId);
        // 获取根路径
        this.rootPath = fileSystem.getRootPath();
    }


    /**
     * 上传文章文件至对应数据
     *
     * @param multipartFile
     */
    public CommonResult<WebFile> upload(MultipartFile multipartFile, Long fkObjectId) {
        try {
            // 判断文件是否为空
            if (ObjectUtil.isNull(multipartFile)) {
                return CommonResult.fail().setText("文件为空");
            }
            // 初始化文件信息
            WebFile webFile = init(multipartFile, fkObjectId);
            if (webFile == null) {
                return CommonResult.fail().setText("创建系统文件失败");
            }
            // 保存文件信息
            if (!iwebFileService.save(webFile)) {
                return CommonResult.fail().setText("保存系统文件失败");
            }
            // 保存文件
            try (OutputStream os = new FileOutputStream(new File(webFile.getUploadPath()))) {
                IoUtil.copy(multipartFile.getInputStream(), os);
                os.flush();
            }
            return CommonResult.ok().setResult(webFile);
        } catch (Exception e) {
            e.printStackTrace();
            return CommonResult.fail().setText("系统异常");
        }
    }


    /**
     * 删除文件
     *
     * @param fileId 文件id
     */
    public synchronized CommonResult delete(Long fileId) {
        //查询文件
        WebFile file = iwebFileService.getById(fileId);
        //删除文件
        boolean state = iwebFileService.removeById(fileId);
        if (!state) {
            return CommonResult.fail().setText("删除文件失败");
        }
        //获取文件路径
        String filePath = rootPath + file.getFilePath();
        //异步删除文件
        new Thread(new DeleteFileTool(filePath)).start();
        return CommonResult.ok();
    }

    /**
     * 下载文件
     *
     * @param id       文件id
     * @param response httpResponse
     */
    public synchronized void download(Long id, HttpServletResponse response) {
        try {
            // 设置响应类型
            response.setContentType("application/octet-stream");
            // 设置编码格式
            response.setCharacterEncoding("UTF-8");
            // 根据id获取文件
            WebFile webFile = iwebFileService.getById(id);
            if (webFile == null) {
                return;
            }
            // 拼接文件路径
            String path = String.format("%s%s", rootPath, webFile.getFilePath());

            // 编码文件名
            String encodedFilename = URLEncoder.encode(webFile.getOriginalName(), "UTF-8");
            // 拼接文件名
            String filename = encodedFilename + "." + webFile.getSuffix();
            // 设置响应头
            response.setHeader("Content-Disposition", "attachment;filename=\"" + filename + "\"");

            try (InputStream inputStream = new FileInputStream(path);
                 OutputStream outputStream = response.getOutputStream()) {
                // 定义缓冲区
                byte[] buffer = new byte[1024];
                int length;
                // 循环读取文件
                while ((length = inputStream.read(buffer)) != -1) {
                    // 写入响应流
                    outputStream.write(buffer, 0, length);
                }
                // 刷新缓冲区
                outputStream.flush();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 下载文件
     *
     * @param filePath 文件路径
     * @param response httpResponse
     */
    public synchronized void download(String filePath, HttpServletResponse response,String fileName) {
        try {
            // 设置响应类型
            response.setContentType("application/octet-stream");
            // 设置编码格式
            response.setCharacterEncoding("UTF-8");
            // 设置响应头
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            try (InputStream inputStream = new FileInputStream(filePath);
                 OutputStream outputStream = response.getOutputStream()) {
                // 定义缓冲区
                byte[] buffer = new byte[1024];
                int length;
                // 循环读取文件
                while ((length = inputStream.read(buffer)) != -1) {
                    // 写入响应流
                    outputStream.write(buffer, 0, length);
                }
                // 刷新缓冲区
                outputStream.flush();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 初始化文件信息
     *
     * @param multipartFile 文件
     */
    private synchronized WebFile init(MultipartFile multipartFile, Long fkObjectId) {
        // 获取文件原始名称
        String originalFilename = multipartFile.getOriginalFilename();
        // 文件后缀
        String suffix = getSuffix(originalFilename);
        // 文件原始名称
        String originalName = removeSuffix(originalFilename, suffix);
        // 文件保存名称
        String fileName = System.currentTimeMillis() + randomUUID() + "." + suffix;
        // 文件大小
        long fileSize = multipartFile.getSize();
        // 获取文件存储地址
        WebFileSystem fileSystem = updateFileSystem();
        if (fileSystem == null) {
            return null;
        }

        String uploadPath = String.format("%s/%s/%s/%s/%s", rootPath, SystemPath.dataFilePath.val, fileSystem.getFolderOne(), fileSystem.getFolderTwo(), fileName);
        String savePath = String.format("/%s/%s/%s/%s", SystemPath.dataFilePath.val, fileSystem.getFolderOne(), fileSystem.getFolderTwo(), fileName);

        WebFile webFile = new WebFile();
        webFile.setFkObjectId(fkObjectId);
        webFile.setName(fileName);
        webFile.setOriginalName(originalName);
        webFile.setFilePath(savePath);
        webFile.setSuffix(suffix);
        webFile.setFileSize(fileSize);
        webFile.setCreateBy(ShiroTools.getId());
        webFile.setCreateTime(LocalDateTime.now());
        webFile.setCreateName(ShiroTools.getName());
        webFile.setIsDel(0);
        webFile.setUploadPath(uploadPath);
        webFile.setSort(1);
        return webFile;
    }


    /**
     * 获取文件存储地址，更新分布式文件
     */
    private synchronized WebFileSystem updateFileSystem() {
        // 查询分布式文件当前存储位置
        WebFileSystem fileSystem = iwebFileSystemService.getById(sysFileId);
        String savePath = String.format("%s/%s/", rootPath, SystemPath.dataFilePath.val);
        // 文件夹不存在 初始化文件夹
        if (!folderExist(savePath)) {
            for (int i = 0; i <= fileSystem.getFolderMax(); i++) {
                for (int j = 0; j <= fileSystem.getFolderMax(); j++) {
                    String folderPath = savePath + i + "/" + j;
                    FileUtil.mkdir(folderPath);
                }
            }
        }

        // 获取每个文件夹标准数量
        int standardCount = fileSystem.getStandardCount();
        // 当前文件夹文件数量加一
        fileSystem.setFileCount(fileSystem.getFileCount() + 1);
        // 当前文件夹数量大于标准数量
        if (fileSystem.getFileCount() > standardCount) {
            fileSystem.setFileCount(0); // 重置当前文件夹文件数量
            fileSystem.setFolderTwo(fileSystem.getFolderTwo() + 1); // 内层文件夹数量+1
        }
        // 内层文件夹数量大于最大文件夹数量
        if (fileSystem.getFolderTwo() > fileSystem.getFolderMax()) {
            fileSystem.setFolderTwo(0);
            fileSystem.setFolderOne(fileSystem.getFolderOne() + 1); // 外层文件夹数量+1
        }
        // 外层文件夹数量大于最大文件夹数量
        if (fileSystem.getFolderOne() > fileSystem.getFolderMax()) {
            fileSystem.setFolderOne(0);
        }
        // 修改当前分布式存储信息
        boolean state = iwebFileSystemService.updateById(fileSystem);
        if (!state) {
            return null;
        }

        return fileSystem;
    }


    /**
     * 根据id获取文件字节
     */
    public byte[] getBytesById(long id) {
        try {
            // 查询文件信息
            WebFile webFile = iwebFileService.getById(id);
            if (webFile == null) {
                return null;
            }
            // 拼接文件路径
            String path = rootPath + webFile.getFilePath();
            Path filePath = Paths.get(path);
            // 读取文件字节
            return Files.readAllBytes(filePath);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }


}
